package com.example.demo.listener;

import com.example.demo.entity.User;
import com.example.demo.event.ArmEvent;
import com.example.demo.event.FaceEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;

@Component
public class FaceListener {
    private static Logger logger = LoggerFactory.getLogger(FaceEvent.class);

    //@TransactionalEventListener和 @EventListener都可以监听事件，但前者可以对发布事件和监听事件进行一些事务上的隔离。
    // 前者指不和发布事件的方法在同一个事务内，发布事件的方法事务结束后才会执行本监听方法，
    // 监听逻辑内发生异常不会回滚发布事件方法的事务。

    //可以看到发布事件的方法处在事务控制中
    @Transactional(rollbackFor = Exception.class)
    public void handle(){
        User user = new User();
        user.setId(123);
        user.setName("jack");

        //处理完上面的逻辑后，发布事件
        EventPublisherUtil.publishEvent(new FaceEvent(user));

        //数据库添加操作
        //Integer integer = deviceAlarmService.addDevice();
    }

    //运行结果，addDevice正常在数据库插入数据，但是修改为@EventListener监听则插入数据失败。
	@TransactionalEventListener(fallbackExecution = true)
	@Order(5)
    public void onApplicationEvent(FaceEvent event) {
        User user = (User) event.getEventData();
        logger.info("===> A 收到人脸事件:  {}}",user);

        //@TransactionalEventListener指不和发布事件的在同一个事务内，发布事件的方法事务结束后才会执行本方法，
        // 本方法发生异常不会回滚发布事件的事务，
        throw new  RuntimeException("监听事件抛出异常");
    }
    //@TransactionalEventListener有一个属性为fallbackExecution，默认为false，指发布事件的方法没有事务控制时，
    // 监听器不进行监听事件，此为默认情况！
    // fallbackExecution=true，则指发布事件的方法没有事务控制时，监听方法仍可以 监听事件进行处理。

    //刚才我们说到使用@TransactionalEventListener会在发布事件的方法事务结束后执行监听方法，但其实我们还可以进行细化的控制。
    // 它有一个属性为TransactionPhase，默认为TransactionPhase.AFTER_COMMIT，即事务提交后。还可以根据需要选择
    // AFTER_COMPLETION、BEFORE_COMMIT、AFTER_ROLLBACK。 但仍需注意，如果fallbackExecution=false，
    //且发布事件的方法没有事务控制时，监听器根本不会监听到事件，此处的TransactionPhase也就没有意义了。

    @EventListener
    @Order(4)
    public void onApplicationEvent1(FaceEvent event) {
        User user = (User) event.getSource();
        logger.info("===> A 收到人脸事件:  {}",user);
    }


    @EventListener({FaceEvent.class,ArmEvent.class})
    @Order(3)
    public void onApplicationEvent3(Object event) {

        if(event instanceof FaceEvent){
            logger.info("===> B 收到人脸事件:  {}",((FaceEvent) event).getEventData());
        }else if(event instanceof ArmEvent){
            ArmEvent armEvent = (ArmEvent) event;
            logger.info("===> B 收到臂膀事件:  {}",armEvent.getEventData());
        }
    }
}